package cn.yangliu.comm.tools;

import cn.yangliu.comm.entity.UploadInfo;
import org.slf4j.LoggerFactory;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.nio.channels.FileChannel;
import java.util.Objects;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * 文件工具类
 */
public class FileUtils {

    private static final org.slf4j.Logger logger = LoggerFactory.getLogger(FileUtils.class);

    /**
     * 删除文件,按文件绝对路径删除
     *
     * @param folderPathAndName
     */
    public static void deleteFile(String folderPathAndName) {
        deleteFile(new File(folderPathAndName));
    }

    /**
     * 删除文件
     *
     * @param file
     */
    public static void deleteFile(File file) {
        if (file == null) {
            throw new RuntimeException("参数不能为空");
        }

        if (!file.exists()) {
            throw new RuntimeException("文件或文件夹不存在");
        }

        if (!file.isFile()) {
            File[] files = file.listFiles();
            if (files != null) {
                for (File file2 : files) {
                    deleteFile(file2);
                }
            }

        }
        file.delete();
    }

    /**
     * 文件夹拷贝
     *
     * @param sourceFolderName 源夹文件名
     * @param targetFolderName 目标夹文件名
     */
    public static void folderCopy(String sourceFolderName, String targetFolderName) {
        File s = new File(sourceFolderName);
        File t = new File(targetFolderName);
        folderCopy(s, t);
    }

    /**
     * 文件夹拷贝
     *
     * @param s 源夹文件
     * @param t 目标夹文件
     */
    public static void folderCopy(File s, File t) {
        if ((s == null) || (t == null)) {
            throw new RuntimeException("参数不能为空");
        }
        if (s.isDirectory()) {
            if (!t.exists()) {
                t.mkdir();
            }
            File[] files = s.listFiles();
            if (files != null) {
                for (File file : files) {
                    folderCopy(file, new File(t.getPath() + File.separator + file.getName()));
                }
            }
        } else {
            fileCopy(s, t);
        }
    }

    /**
     * 文件夹拷贝
     *
     * @param sourcePathAndName 源文件夹路径
     * @param targetPathAndName 目标文件夹路径
     */
    public static void fileCopy(String sourcePathAndName, String targetPathAndName) {
        fileCopy(new File(sourcePathAndName), new File(targetPathAndName));
    }

    /**
     * 文件拷贝
     *
     * @param s 源文件
     * @param t 目标文件
     */
    public static void fileCopy(File s, File t) {
        FileInputStream fi = null;
        FileOutputStream fo = null;
        FileChannel in = null;
        FileChannel out = null;
        try {
            fi = new FileInputStream(s);
            fo = new FileOutputStream(t);
            in = fi.getChannel();
            out = fo.getChannel();
            in.transferTo(0L, in.size(), out);
        } catch (Exception e) {
            logger.error("", e);
            throw new RuntimeException(e);
        } finally {
            try {
                closeStream(fi);
                closeStream(in);
                closeStream(in);
                closeStream(fo);
                closeStream(out);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }

    /**
     * 服务端上传
     * @param file     上传文件
     * @param commPath 公共目录
     * @param subPath  子目录
     * @return 上传文件信息
     */
    public static UploadInfo serverUpload(MultipartFile file, String commPath, String subPath) {
        String savePath;
        if (!commPath.endsWith("/")) {
            savePath = commPath + "/" + subPath;
        } else {
            savePath = commPath + subPath;
        }

        UploadInfo uploadInfo = serverUpload(file, savePath);
        uploadInfo.setPath(subPath);
        return uploadInfo;
    }

    /**
     * 服务端文件上传
     *
     * @param file 上传的文件
     * @param path 上传文件保存路径
     * @return 上传文件的信息
     */
    public static UploadInfo serverUpload(MultipartFile file, String path) {
        if (Objects.isNull(file) || file.getSize() == 0) {
            return null;
        }
        String fileName = file.getOriginalFilename();

        String fileSufix = getFileSufix(file);

        fileName = fileName.substring(0, fileName.lastIndexOf("."));
        String newFileName;
        if (!path.endsWith("/")) {
            path += "/";
        }

        try {
            String tempName = StringUtils.getOrderNo(8);
            newFileName = tempName + "." + fileSufix;
            File targetPath = new File(path);
            if (!targetPath.exists()) {
                targetPath.mkdirs();
            }

            // 保存
            try (FileOutputStream fileOutputStream = new FileOutputStream(path + newFileName)) {
                // 保存
                fileOutputStream.write(file.getBytes());
                fileOutputStream.flush();
                logger.info("保存文件成功===>" + newFileName);

                UploadInfo uploadInfo = new UploadInfo();
                uploadInfo.setSufix("." + fileSufix);
                uploadInfo.setFileName(tempName);
                uploadInfo.setPath(path);
                uploadInfo.setOldName(fileName);
                return uploadInfo;
            } catch (Exception e) {
                throw new RuntimeException(e.getMessage(), e);
            }
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage(), e);
        }

    }


    /**
     * 服务端文件下载
     *
     * @param response 响应
     * @param downName 文件下载名
     */
    public static void serverDownload(HttpServletResponse response, String downName, File file) {
        response.setContentType("application/x-msdownload");
        FileInputStream fis = null;
        OutputStream os = null;
        try {
            response.setHeader("Content-disposition", "attachment; filename="
                    + new String(downName.getBytes("UTF-8"), "ISO8859-1"));
            os = response.getOutputStream();
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(downName, "UTF-8"));
            fis = new FileInputStream(file);
            byte[] buffer = new byte[2048];
            int length = 0;
            while ((length = fis.read(buffer)) != -1) {
                os.write(buffer, 0, length);
            }
        } catch (Exception e) {
            logger.error("下载失败", e);
            throw new RuntimeException(e);
        } finally {
            closeStream(fis);
            closeStream(os);
        }
    }

    private static void closeStream(Closeable closeable) {
        if (Objects.nonNull(closeable)) {
            try {
                closeable.close();
            } catch (Exception e) {
                throw new RuntimeException(e.getMessage(), e);
            }
        }
    }

    /**
     * 服务端文件下载
     *
     * @param response    响应
     * @param downName    文件下载名
     * @param pathAndName 文件存储路径
     */
    public static void serverDownload(HttpServletResponse response, String downName, String pathAndName) {
        response.setContentType("application/x-msdownload");
        FileInputStream fis = null;
        OutputStream os = null;
        try {
            response.setHeader("Content-disposition", "attachment; filename="
                    + new String(downName.getBytes("UTF-8"), "ISO8859-1"));
            os = response.getOutputStream();
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(downName, "UTF-8"));
            fis = new FileInputStream(new File(pathAndName));
            byte[] buffer = new byte[2048];
            int length = 0;
            while ((length = fis.read(buffer)) != -1) {
                os.write(buffer, 0, length);
            }
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            throw new RuntimeException(e.getMessage(), e);
        } finally {
            closeStream(fis);
            closeStream(os);
        }
    }

    /**
     * 服务端下载
     */
    public static void serverDownload(HttpServletRequest request, HttpServletResponse response, String contentType,
                                String fileName, String basePath) {

        BufferedInputStream bis = null;
        BufferedOutputStream bos = null;

        try {
            request.setCharacterEncoding("UTF-8");
            String ctxPath = request.getSession().getServletContext().getRealPath("/") + basePath;
            String downLoadPath = ctxPath + fileName;

            File file = new File(downLoadPath);
            long fileLength = file.length();

            response.setContentType(contentType);
            response.setHeader("Content-disposition", "attachment; filename="
                    + new String(fileName.getBytes("UTF-8"), "ISO8859-1"));
            response.setHeader("Content-Length", String.valueOf(fileLength));

            bis = new BufferedInputStream(new FileInputStream(file));
            bos = new BufferedOutputStream(response.getOutputStream());
            byte[] buff = new byte[2048];
            int bytesRead;
            while (-1 != (bytesRead = bis.read(buff, 0, buff.length))) {
                bos.write(buff, 0, bytesRead);
            }
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage(), e);
        } finally {
            closeStream(bis);
            closeStream(bos);
        }

    }


    public static String getFileSufix(MultipartFile file) {
        String file_name = file.getOriginalFilename();
        return getFileSufix(file_name);
    }

    public static String getFileSufix(String filename) {
        return filename.substring(filename.lastIndexOf(".") + 1);
    }

    /**
     * 将存放在sourceFilePath目录下的源文件，打包成fileName名称的zip文件，并存放到zipFilePath路径下
     *
     * @param sourceFilePath :待压缩的文件路径
     * @param zipFilePath    :压缩后存放路径
     * @param fileName       :压缩后文件的名称
     * @return
     */
    public static boolean fileToZip(String sourceFilePath, String zipFilePath, String fileName) {
        boolean flag = false;
        File sourceFile = new File(sourceFilePath);
        FileInputStream fis = null;
        BufferedInputStream bis = null;
        FileOutputStream fos = null;
        ZipOutputStream zos = null;
        try {
            File zipFile = new File(zipFilePath + "/" + fileName + ".zip");
            if (zipFile.exists()) {
                logger.info(zipFilePath + "目录下存在名字为:" + fileName + ".zip" + "打包文件.");
            } else {
                File[] sourceFiles = sourceFile.listFiles();
                if (Objects.isNull(sourceFiles) || sourceFiles.length < 1) {
                    logger.info("待压缩的文件目录：" + sourceFilePath + "里面不存在文件，无需压缩.");
                } else {
                    fos = new FileOutputStream(zipFile);
                    zos = new ZipOutputStream(new BufferedOutputStream(fos));
                    byte[] bufs = new byte[1024 * 10];
                    for (int i = 0; i < sourceFiles.length; i++) {
                        //创建ZIP实体，并添加进压缩包
                        ZipEntry zipEntry = new ZipEntry(sourceFiles[i].getName());
                        zos.putNextEntry(zipEntry);
                        //读取待压缩的文件并写进压缩包里
                        fis = new FileInputStream(sourceFiles[i]);
                        bis = new BufferedInputStream(fis, 1024 * 10);
                        int read = 0;
                        while ((read = bis.read(bufs, 0, 1024 * 10)) != -1) {
                            zos.write(bufs, 0, read);
                        }
                    }
                    flag = true;
                }
            }
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage(), e);
        } finally {
            //关闭流
            closeStream(bis);
            closeStream(zos);
        }

        return flag;
    }
}